package pl.edu.mimuw.mas.gui;

import jade.core.Agent;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.LinkedList;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.GroupLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import pl.edu.mimuw.mas.tools.PeriodModifier;

/**
 * Główne okno zawierające zarządce zakładek - agent ma jedną lub więcej
 * zakładek które kontroluje.
 */
@SuppressWarnings("serial")
public class MainWindow extends JFrame implements ITabContener {

	private static final int MAX = 10;
	private static final String SPEED_INFO = "aktualna prędkość ";
	
	// tabs
	private final LinkedList<TabTuple> tabsBuffer;
	private final JTabbedPane tabs;
	
	// speed bar
	private final JLabel speedInfo;
	private final JLabel speedValue;
	private final JSlider speedSelector;
	private final PeriodModifier speedModifier;

	public MainWindow(String title, int x, int y, PeriodModifier modifier) {
		super(title);

		// tabs
		this.tabsBuffer = new LinkedList<TabTuple>();
		this.tabs = new JTabbedPane();
		this.tabs.setName("tabs");

		// speed
		this.speedModifier = modifier;
		
		this.speedSelector = new JSlider(-MAX, MAX, 0);
		this.speedSelector.setMaximumSize(new Dimension(400, 20));
		this.speedSelector.setPreferredSize(new Dimension(400, 20));
		this.speedSelector.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				double newScale;
				if (speedSelector.getValue() >= 1) {
					newScale = 1.0 / speedSelector.getValue();
				} else if (speedSelector.getValue() != speedSelector.getMinimum()) {
					newScale = 1.0 - speedSelector.getValue();
				} else {
					newScale = Double.POSITIVE_INFINITY;
				}
				speedModifier.setScale(newScale);
				speedValue.setText(getScaleValueText());
			}
		});
		
		this.speedInfo = new JLabel(SPEED_INFO);
		this.speedValue =  new JLabel();
		
		Font f = this.speedValue.getFont();
		this.speedValue.setFont(f.deriveFont(f.getStyle() ^ Font.BOLD));
		this.speedValue.setText(getScaleValueText());

		// layout
		JPanel speedPanel = new JPanel();
		speedPanel.setLayout(new BoxLayout(speedPanel, BoxLayout.LINE_AXIS));
		speedPanel.add(speedSelector);	
		speedPanel.add(Box.createHorizontalGlue());
		speedPanel.add(speedInfo);
		speedPanel.add(speedValue);		
					
		GroupLayout mainWindowLayout = new GroupLayout(this.getContentPane());
		
		mainWindowLayout.setHorizontalGroup(
				mainWindowLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
					.addComponent(tabs)
					.addComponent(speedPanel));

		mainWindowLayout.setVerticalGroup(
				mainWindowLayout.createSequentialGroup()
					.addComponent(tabs)
					.addComponent(speedPanel));
		
		this.setSize(x, y);
		this.getContentPane().setLayout(mainWindowLayout);
		
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				for(TabTuple tab : tabsBuffer) {
					Agent a = tab.getAgent();
					if(a != null) {
						a.doDelete();
					}
					
				}
			}
		});
		
		this.showWindow();
	}

	private String getScaleValueText() {
		String text = Double.toString(1.0 / speedModifier.getScale());
		
		if (speedModifier.getScale() > 1) {
			text = text.substring(0, Math.min(4, text.length()));
		}				
		return "x" + text;
	}
	
	public void addTab(Agent myagent, String name, JPanel panel) {
		synchronized (tabsBuffer) {

			boolean flag = false;
			TabTuple tab = new TabTuple(myagent, name, panel);

			int i = 0;
			while (!flag && i < tabsBuffer.size()) {
				if (tab.compareTo(tabsBuffer.get(i)) <= 0) {
					tabsBuffer.add(i, tab);
					flag = true;
				}
				i++;
			}

			if (!flag) {
				tabsBuffer.add(tab);
			}

			refreshTabs();
		}
	}
	
	public void addTab(String name, JPanel panel) {		
		addTab(null, name, panel);
	}
	
	private void refreshTabs() {
		tabs.removeAll();
		for(TabTuple tab : tabsBuffer) {
			tabs.add(tab.getName(), tab.getPanel());
		}
	}
	
	public void showWindow() {
		setVisible(true);
	}

	public void closeWindow() {
		setVisible(false);
		dispose();
	}
}
